package cn.qixin.passport.service.impl;


import cn.qixin.passport.ex.ServiceException;
import cn.qixin.passport.mapper.UserMapper;
import cn.qixin.passport.mapper.UserRoleMapper;
import cn.qixin.passport.pojo.dto.UserAddNewDTO;
import cn.qixin.passport.pojo.dto.UserLoginDTO;
import cn.qixin.passport.pojo.dto.UserUpdateDTO;
import cn.qixin.passport.pojo.entity.QxUser;
import cn.qixin.passport.pojo.entity.UserRole;
import cn.qixin.passport.pojo.vo.UserListItemVO;
import cn.qixin.passport.pojo.vo.UserStandardVO;
import cn.qixin.passport.security.QxUserDetails;
import cn.qixin.passport.service.IUploadService;
import cn.qixin.passport.service.IUserService;
import cn.qixin.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;


@Slf4j
@Service
public class  UserServiceImpl implements IUserService {

    @Autowired
    IUploadService uploadService;
    @Autowired
    UserMapper userMapper;
    @Autowired
    UserRoleMapper userRoleMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Value("${qixin.jwt.secret-key}")
    private String secretKey;
    @Value("${qixin.jwt.duration-in-minute}")
    private long durationInMinute;
    @Autowired
    RedisTemplate<String, String> redisTemplate;
    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public String login(UserLoginDTO userLoginDTO) {
        log.debug("开始处理【管理员登录】的业务，参数：{}", userLoginDTO);
        Authentication authentication
                = new UsernamePasswordAuthenticationToken(
                userLoginDTO.getUsername(), userLoginDTO.getPassword());
        log.debug("开始跳转到UserDetailsServiceImpl中对用户进行验证");
        Authentication authenticateResult = authenticationManager.authenticate(authentication);

        Object principal = authenticateResult.getPrincipal();
        log.debug("认证结果中的当事人类型：{}", principal.getClass().getName());
        QxUserDetails user = (QxUserDetails) principal;
        Long id = user.getId();
        String username = user.getUsername();
        Collection<GrantedAuthority> authorities = user.getAuthorities();
        String authoritiesJsonString = JSON.toJSONString(authorities);


        Map<String, Object> claims = new HashMap<>();
        claims.put("username", username);
        claims.put("id", id);
        claims.put("authoritiesJsonString", authoritiesJsonString);
        Date date = new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000L);
        String jwt = Jwts.builder()
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                .setClaims(claims)
                .setExpiration(date)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        log.debug("生成的JWT：{}", jwt);
        return jwt;
    }

    @Override
    public void addNew(UserAddNewDTO userAddNewDTO) {
        log.debug("开始处理添加用户功能,参数{}", userAddNewDTO);
        log.debug("开始验证手机号是否重复");
        {
            String phone = userAddNewDTO.getPhone();
            int rows = userMapper.countByPhone(phone);
            if (rows > 0){
                String message = "添加用户失败，手机号码【" + phone + "】已经被占用！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }
        log.debug("开始验证用户名是否重复");
        {
            String username = userAddNewDTO.getUsername();
            int rows = userMapper.countByUsername(username);
            if (rows > 0){
                String message = "添加用户失败，用户名【" + username + "】已经被占用！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        QxUser qxUser = new QxUser();
        //获取当前时间
        // 通过BeanUtils.copyProperties()方法将参数对象的各属性值复制到Admin对象中
        BeanUtils.copyProperties(userAddNewDTO, qxUser);
        // 从QxUser对象中取出密码，进行加密处理，并将密文封装回QxUser对象中
        // 取出密码，进行加密处理，并将密文封装回QxUser对象中
        String rawPassword = qxUser.getPassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);
        qxUser.setPassword(encodedPassword);

        qxUser.setNickname("普通用户");
        qxUser.setVip(0);
        qxUser.setEnable(1);

        log.debug("即将添加用户数据");
        String code = userAddNewDTO.getCode();
        //取出redis中的数据
        String redisCode  = redisTemplate.opsForValue().get(userAddNewDTO.getEmail());
        System.out.println("redis使用的key为:"+userAddNewDTO.getEmail());
        log.info("redis中取出的验证码为：{}",redisCode);
        log.info("用户输入的验证码为：{}",code);
        log.info("用户接受验证码的邮箱为：{}",userAddNewDTO.getEmail());
        if(redisCode != null){
            if (redisCode.equals(code)){//判断输入的邮箱和验证码
                log.debug("即将插入用户数据,{}", qxUser);
                int rows = userMapper.insert(qxUser);
                if (rows != 1){
                    String message = "添加用户失败，服务器忙，请稍后再次尝试！";
                    log.warn(message);
                    throw new ServiceException(ServiceCode.ERR_INSERT, message);
                }
            }else {
            log.warn("验证码错误");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,"验证码错误！");
            }
        } else {
            log.warn("验证码为空");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,"账号或验证码错误！");
        }


        log.debug("开始添加角色信息");
        userAddNewDTO.setRoleId(new Long[]{3L});
        Long [] roleIdS = userAddNewDTO.getRoleId();

        //系统管理员(roleId=1)只允许有一个
        for (int i = 0; i < roleIdS.length; i++) {
            if (roleIdS [i] == 1){
                String message = "添加用户失败，非法访问！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_INSERT, message);
            }
        }

        List<UserRole> userRoleList = new ArrayList<>();
        for (int i = 0; i < roleIdS.length; i++) {
            UserRole userRole = new UserRole();
            userRole.setUserId(qxUser.getId());
            userRole.setRoleId(roleIdS[i]);//遍历数组中的角色id
            userRoleList.add(userRole);
        }
        int rows = userRoleMapper.insertBatch(userRoleList);
        if (rows != roleIdS.length){
            String message = "添加用户失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

    }

    @Override
    public void deleteById(Long id) {
        log.debug("开始处理删除用户功能");
        //查询被删除的角色是否存在
        UserStandardVO queryResult = userMapper.getStandardById(id);
        if (queryResult == null){
            String message = "删除用户失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        //系统管理员不允许被删除
        if (id.equals(1)) {
            String message = "删除用户失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

        //删除用户数与预期不符合
        int rows = userMapper.deleteById(id);
        if (rows != 1){
            String message = "删除用户失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
    }

    @Override
    public void update(Long id, UserUpdateDTO userUpdateDTO) {
        UserStandardVO standardById = userMapper.getStandardById(id);
        if(standardById==null){
            String message = "修改用户详情失败，尝试访问的数据不存在！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        {
            int countByUsername = userMapper.countByUsername(userUpdateDTO.getUsername());
            if(countByUsername>0){
                String message = "修改用户详情失败，名字已存在！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        QxUser qxUser=new QxUser();


        BeanUtils.copyProperties(userUpdateDTO,qxUser);
        qxUser.setId(id);
        int update = userMapper.updateById(qxUser);
        if (update != 1) {
            String message = "修改用户失败，服务器忙，请稍后再次尝试！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    @Override
    public UserStandardVO getStandardById(Long id) {
        log.debug("开始处理【根据id查询用户详情】的业务");
        UserStandardVO standardById = userMapper.getStandardById(id);
        if(standardById==null){
            String message="查询的id不存在";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        return standardById;
    }

    @Override
    public List<UserListItemVO> list() {
        log.debug("开始处理展示用户列表功能");
        List<UserListItemVO> list = userMapper.list();
        //使用迭代器实现列表不显示系统管理员
        Iterator<UserListItemVO> iterator = list.iterator();
        while (iterator.hasNext()){
            UserListItemVO itemVO = iterator.next();
            if (itemVO.getId() == 1){
                iterator.remove();
                break;
            }
        }
        return list;
    }

}
